#include <unordered_map>
#include <Projectile.h>
#include <Player.h>
#include <Level.h>

using namespace std;

extern int gameTick;

// maxAmmo, coldDown, hitPoints, primarySpeed, refreshTime, hitRange, lifeTime
// count, velocityDecreasePerRound, randomspreadRange, randomspreadAngle, velocityChangePerSec

// 需要规范化读取

const float PI = 3.1415926f;
//   name                  mAmmo  CD   damage  pSpeed  rT range lifeT  cnt vDpR  spR spA         vCPS
unordered_map<string, ProjectileData> bulletDatas = {
    { "normal_bullet",    { 1,   0.25f, 10.0f, 250.0f, 1, 10.0f, 3.0f,  1, 0,     0,  0,          0} },
    { "reimu_spellcard",  { 30,  0.2f,  20.0f, 160.0f, 2, 10.0f, 4.5f,  1, 0,     0,  PI / 18.0f, -15.0f } },
    { "marisa_star",      { 50,  0.15f, 12.0f, 140.0f, 2, 15.0f, 2.5f,  1, 0,     0,  PI / 15.0f, 75.0f } },
    { "reimilia_arrow",   { 8,   1.5f,  15.5f, 110.0f, 1, 14.0f, 4.0f,  9, 0,     50, PI / 6.0f,  70.0f } },
    { "cirno_ice",        { 12,  0.9f,  18.0f, 180.0f, 2, 14.0f, 3.0f,  8, 25.0f, 0,  0,          0 } },
    { "alice_doll",       { 2,   0.25f, 5.0f,  30.0f,  1, 12.0f, 8.0f,  1, 0,     0,  0,          0 } },
    { "keine_mirror",     { 20,  0.4f,  21.0f, 300.0f, 1, 18.0f, 2.0f,  1, 0,     0,  PI / 15.0f, -100.0f } },
    { "keine_mirror_sub", { 20,  0.4f,  15.0f, 40.0f,  1, 18.0f, 3.5f,  2, 0,     0,  PI / 10.0f, 100.0f } },
    { "mokou_flame",      { 150, 0.05f, 7.5f,  260.0f, 2, 18.0f, 0.35f, 1, 0,     0,  PI / 5.0f,  -340.0f } },
    { "sanae_star",       { 7,   1.15f, 12.5f, 290.0f, 2, 15.0f, 4.0f,  8, 24.0f, 3,  PI / 10.0f, -50.0f } },
    { "koishi_love",      { 5,   1.85f, 85.0f, 280.0f, 4, 10.0f, 3.0f,  1, 0,     0,  0,          0 } },
    { "murasa_anchor",    { 1,   1.5f,  65.0f, 50.0f,  1, 18.0f, 6.0f,  1, 0,     0,  0,          70.0f } },
    { "murasa_anchor_sub",{ 1,   1.5f,  12.0f, 145.0f, 1, 12.0f, 2.5f,  2, 0,     0,  PI / 9.0f,  120.0f } },
    { "seija_arrow",      { 45,  0.18f, 19.0f, 70.0f,  2, 13.0f, 2.8f,  1, 0,     0,  PI / 14.0f, 130.0f } },
    { "doremy_catcher",   { 5,   1.2f,  21.0f, 110.0f, 2, 17.0f, 4.8f,  1, 0,     0,  0,          20.0f } },
    { "okina_star",       { 2,   3.5f,  21.0f, 210.0f, 2, 14.0f, 4.8f,  6, 41.0f, 0,  0,          30.0f } },
    { "yachie_shield",    { 25,  0.5f,  17.0f, 250.0f, 1, 15.0f, 1.2f,  1, 0,     0,  0,          -150.0f } },
    { "yachie_shield_sub",{ 3,   1.2f,  15.0f, 230.0f, 2, 13.0f, 1.2f,  1, 0,     0,  0,          -130.0f } },
    { "zanmu_ghost",      { 80,  0.11f, 11.5f, 40.0f,  2, 17.0f, 3.5f,  1, 0,     0,  PI / 14.0f, 125.0f } },
};
// 这部分需要扩充

void Projectile::fillBullet(string bulletType, string uuid, Vector2 pos, string ownerUuid) {
    this->bulletType = bulletType;
    this->uuid = uuid;
    this->pos = pos;
    velocity = Vector2 { 0, 0 };
    this->ownerUuid = ownerUuid;
    hitPoints = bulletDatas[bulletType].hitPoints;
    hitRange = bulletDatas[bulletType].hitRange;
    lifeTime = bulletDatas[bulletType].lifeTime;
    refreshTime = bulletDatas[bulletType].refreshTime;
}

void Projectile::setVelocity(Vector2 direction) {
    direction.normalize();
    direction.mult(bulletDatas[bulletType].primarySpeed);
    if (direction.returnLength() < __FLT_EPSILON__) {
        direction = Vector2 { bulletDatas[bulletType].primarySpeed, 0 };
    }
    velocity = direction;
}

void Projectile::setVelocity(Vector2 direction, float speed) {
    direction.normalize();
    direction.mult(speed);
    if (direction.returnLength() < __FLT_EPSILON__) {
        direction = Vector2 { speed, 0 };
    }
    velocity = direction;
}

void Projectile::Update(const float rate, queue<LevelAction> &responseBuffer) {
    for (int i = 1; i <= refreshTime; i++) {
        pos.x += velocity.x * rate;
        pos.y += velocity.y * rate;
    }
    if (gameTick % 20 == 0 || (bulletType == "murasa_anchor" && gameTick % 2 == 0)) {
        vector<string> posInfo { uuid, to_string(pos.x), to_string(pos.y),
            to_string(velocity.x), to_string(velocity.y) };
        pushToResponseBuffer("pja", posInfo, responseBuffer);
    }
    lifeTime -= rate;
}

void Projectile::printProjectileInfo() {
    printf("%s(owner:%s) -> pos:(%f, %f); velocity:(%f, %f); hitPoints:%f; angle:(%f); lifeTime:%f \n",
    uuid.c_str(), ownerUuid.c_str(), pos.x, pos.y, velocity.x, velocity.y, hitPoints, angle, lifeTime);
}

Weapon returnWeapon(string bulletType) {
    Weapon targetWeapon;
    targetWeapon.bulletType = bulletType;
    targetWeapon.maxAmmo = bulletDatas[bulletType].maxAmmo;
    targetWeapon.ammo = targetWeapon.maxAmmo;
    targetWeapon.maxColdDown = bulletDatas[bulletType].coldDown;
    targetWeapon.coldDown = targetWeapon.maxColdDown;
    return targetWeapon;
}

void Item::fillItem(string uuid, Vector2 pos) {
    this->uuid = uuid;
    this->pos = pos;
    velocity = Vector2 { 0, 0 };
}

void Item::setVelocity() {
    float angle = (float)(rand() % 1000) / 1000.0f * 3.1415926f * 2.0f;
    Vector2 direction = Vector2 { cos(angle), sin(angle) };
    direction.mult(50.0f);
    velocity = direction;
}

void Item::Update(const float rate, queue<LevelAction> &responseBuffer) {
    // 只需要指示位置的改变
    pos.x += velocity.x * rate;
    pos.y += velocity.y * rate;
    if (gameTick % 30 == 0) {
        vector<string> posInfo { uuid, to_string(pos.x),
            to_string(pos.y), to_string(velocity.x), to_string(velocity.y) };
        pushToResponseBuffer("ia", posInfo, responseBuffer);
    }
    lifeTime -= rate;
}

void Item::printItemInfo() {
    printf("%s -> pos:(%f, %f); velocity:(%f, %f); lifeTime:%f \n",
    uuid.c_str(), pos.x, pos.y, velocity.x, velocity.y, lifeTime);
}
